package qmlt.learning.svm;

import java.io.IOException;

import libsvm.svm;
import libsvm.svm_model;
import libsvm.svm_node;
import libsvm.svm_parameter;
import libsvm.svm_problem;

import qmlt.dataset.DataSet;
import qmlt.dataset.Instance;
import qmlt.learning.Learner;

public class SVM implements Learner<SVMController>
{

	private svm_model model;
	private svm_parameter	param;
	
	@Override
	public Object predict(Instance instance)
	{
		svm_node[] nodes = convertInstanceIntoSVMNodes(instance, instance.getFeatures().size());
		Object rst = null;
		if (param.probability == 1)
		{
			double[] p = new double[1];
			svm.svm_predict_probability(model, nodes, p);
			rst = p[0];
		}
		else
		{
			rst = (float) svm.svm_predict(model, nodes);
		}
		return rst;
	}

	@Override
	public void train(DataSet trainSet, SVMController controller)
	{
		svm_problem problem = constructSVMProblem(trainSet);
		param = controller.param;
		model = svm.svm_train(problem, param);
	}

	@Override
	public void loadModel(String inputFilepath)
	{
		try
		{
			model = svm.svm_load_model(inputFilepath);
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void saveModel(String outputFilepath)
	{
		try
		{
			svm.svm_save_model(outputFilepath, model);
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected static svm_problem constructSVMProblem(DataSet trainSet)
	{
		svm_problem prob = new svm_problem();
		prob.l = trainSet.getInstances().size();
		prob.x = new svm_node[prob.l][];
		prob.y = new double[prob.l];
		for (int i = 0; i < prob.l; ++i)
		{
			Instance instance = trainSet.getInstances().get(i);
			prob.x[i] = convertInstanceIntoSVMNodes(instance, trainSet.getFeatureDefs().size());
			prob.y[i] = (double)(Float) instance.getTarget();
		}
		return prob;
	}

	protected static svm_node[] convertInstanceIntoSVMNodes(Instance instance, int featureDim)
	{
		svm_node[] nodes = new svm_node[featureDim];
		for (int j = 0; j < featureDim; ++j)
		{
			nodes[j] = new svm_node();
			nodes[j].index = j + 1;
			nodes[j].value = (double)(Float) instance.getFeatures().get(j);
		}
		return nodes;
	}
	
}
